#include "log4x-c.h"
#include "log4x.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string>

#ifdef WIN32
#if !(__MINGW32__ && (__GNUC__ == 4) && (__GNUC_MINOR__ == 4) &&  (__GNUC_PATCHLEVEL__ == 0))
#define snprintf_s  _snprintf_s
#define vsnprintf_s vsnprintf_s
#else
#define snprintf_s  snprintf
#define vsnprintf_s vsnprintf
#endif

#else
#define snprintf_s  snprintf
#define vsnprintf_s vsnprintf
#endif
using namespace log4x;

namespace log4x
{
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
int vestimate(const char *format, va_list ap);
int vpush(const char * key, int level, const char * func, const char * file, int line, bool sync, const char* fmt, va_list ap);
}

LOG4X_API int
log4x_init()
{
    ilog4x *i = ilog4x::instance();
    if (i->config("log.ini") < 0)
    {
        return -1;
    }

    return i->start();
}

LOG4X_API void 
log4x_uninit()
{
    ilog4x::instance()->stop();
}

LOG4X_API int
log4x_config(const char * path)
{
    return ilog4x::instance()->config(path);
}

LOG4X_API int
log4x_config_fromstr(const char * str)
{
    return ilog4x::instance()->configFromString(str);
}

LOG4X_API int
log4x_push(const char * key, int level, const char * func, const char * file, int line, bool sync, const char* fmt, ...)
{
#if 1
    std::string text;
    va_list args;
    va_start(args, fmt);
    int estsize = vestimate(fmt, args);
    va_end(args);

    do
    {
        int size   = 1024 * 4;
        int result = -1;
        if (estsize > 0 && estsize < size)
        {
            char buf[1024 * 4] = {0};
            va_start(args, fmt);
            result = log4x::vsnprintf(buf, sizeof(buf), fmt, args);
            va_end(args);

            if (result >= 0)
            {
                text = buf;
                break;
            }
        }

        if (estsize > 10 * 1024 * 1024)
        {
            printf("[%s] too large input data: %s [%s:%d]\r\n", __FUNCTION__, key, __FILE__, __LINE__);
            return -1;
        }

        size = estsize + 100;
        char *p = (char *)::malloc(size);
        if (!p)
        {
            printf("[%s] malloc memery failed: %s [%s:%d]\r\n", __FUNCTION__, key, __FILE__, __LINE__);
            return -1;
        }

        va_start(args, fmt);
        result = log4x::vsnprintf(p, size, fmt, args);
        va_end(args);

        if (result < 0)
        {
            ::free(p);
            return -1;
        }
        text = p;
        ::free(p);
    }
    while (0);

    return ilog4x::instance()->push(key, level, func, file, line, sync, "%s", text.c_str());
#else
    /* note: do not work for Linux */
    va_list args;
    va_start(args, fmt);
    int result = vpush(key, level, func, file, line, sync, fmt, args);
    va_end(args);
    return result;
#endif
}

LOG4X_API int
log4x_enable(const char * key, bool enable)
{
    return ilog4x::instance()->enable(key, enable);
}

LOG4X_API int
log4x_setlevel(const char * key, int level)
{
    return ilog4x::instance()->setLevel(key, level);
}

LOG4X_API int
log4x_setdisplay(const char * key, bool enable)
{
    return ilog4x::instance()->setDisplay(key, enable);
}

LOG4X_API int
log4x_setfileline(const char * key, bool enable)
{
    return ilog4x::instance()->setFileLine(key, enable);
}

LOG4X_API int
log4x_setprocfile(const char * key, bool enable)
{
    return ilog4x::instance()->setProcFile(key, enable);
}

LOG4X_API bool
log4x_isff(const char * key)
{
    return ilog4x::instance()->isff(key);
}

LOG4X_API int
log4x_info(const char * key, const char* fmt, ...)
{
    ilog4x::instance()->setFileLine(key, false);

    char buf[1024 * 4] = {0};

    va_list args;
    va_start(args, fmt);
    int length = log4x::vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);

    if (length < 0)
    {
        return -1;
    }

    return ilog4x::instance()->push(key, LOG_LEVEL_INFO, NULL, NULL, 0, false, buf);
}
